﻿using Abp.Dependency;
using Abp.Runtime.Caching;
using Abp.Runtime.Security;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Configuration;
using Partner.Utility;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Threading;
using System.Threading.Tasks;
using Abp.Localization;
using HCD.Const;

namespace HCD.Web.Authorizer
{
    public class AuthorFilter : IAsyncAuthorizationFilter, ITransientDependency
    {
        private readonly ICacheManager _cacheManager;
        private readonly IConfiguration _configuration;
        private readonly ILocalizationManager _localizationMgr ;

        public AuthorFilter(ICacheManager CacheManager, IConfiguration Configuration,ILocalizationManager localizationMgr)
        {
            _cacheManager = CacheManager;
            _configuration = Configuration;
            _localizationMgr = localizationMgr;
        }
        /// <summary>
        /// 验证
        /// </summary>
        /// <param name="context"></param>
        public async Task OnAuthorizationAsync(AuthorizationFilterContext context)
        {
            //匿名访问特性
            if ((context.ActionDescriptor as ControllerActionDescriptor).MethodInfo.CustomAttributes.Any(a => a.AttributeType == typeof(AllowAnonymousAttribute)) 
            || (context.ActionDescriptor as ControllerActionDescriptor).MethodInfo.ReflectedType.CustomAttributes.Any(a => a.AttributeType == typeof(AllowAnonymousAttribute)))
            {
                return;
            }
            //验证token
            var token = GetToken(context);
            var auth = new AuthModel();
            try
            {
                auth = JWTUtil.DecodeToken(token);
                if (auth.Exp < DateTime.Now)
                    throw new BizException( _localizationMgr.GetString(EnterpriseConsts.LocalizationSourceName, "SessionTimeout"));

                List<Claim>  claims = new List<Claim>();
                claims.Add(new Claim(AbpClaimTypes.UserId, auth.Id.ToString()));
                claims.Add(new Claim(AbpClaimTypes.UserName, auth.UserName));
                if (auth.TenantID.HasValue)
                {
                    claims.Add(new Claim(AbpClaimTypes.TenantId, auth.TenantID.ToString()));
                }
                var identity = new ClaimsIdentity(claims);
                var principal = new ClaimsPrincipal(identity);
                Thread.CurrentPrincipal = principal;
                context.HttpContext.User.AddIdentity(identity);
                context.RouteData.Values.Add("auth", auth);
            }
            catch
            {
                TokenError(context);
                return;
            }

            //如需验证更细致的权限，再扩展
            //PermissionError(context);
            //var ac = (context.ActionDescriptor as ControllerActionDescriptor).MethodInfo.CustomAttributes.Where(at => at.AttributeType == typeof(PermissionAttribute));
            //var co = (context.ActionDescriptor as ControllerActionDescriptor).MethodInfo.ReflectedType.CustomAttributes.Where(at => at.AttributeType == typeof(PermissionAttribute));
            ////需要验证权限
            //if (ac.Any() || co.Any())
            //{

            //}
        }

        private string GetToken(AuthorizationFilterContext context)
        {
            if (!context.HttpContext.Request.Cookies.TryGetValue("ck_token", out string token))
            {
                token = context.HttpContext.Request.Headers["token"];
            }
            return token;
        }

        private void TokenError(AuthorizationFilterContext context)
        {
            //是否为api接口
            var isApi = (context.ActionDescriptor as ControllerActionDescriptor).MethodInfo.ReflectedType.IsDefined(typeof(ApiControllerAttribute), true);
            //是否为ajax请求
            var isAjax = context.HttpContext.Request.Headers["x-requested-with"].Equals("XMLHttpRequest");
            if (isApi || isAjax)
            {
                context.HttpContext.Response.StatusCode = 401;
                context.Result = new ObjectResult(new BaseBizResult{ Success = false, Message = _localizationMgr.GetString(EnterpriseConsts.LocalizationSourceName, "AuthFailed")});
            }
            else//页面请求重定向
            {
                //租户
                context.Result = new RedirectResult("/Home/Error");
            }
        }

        private void PermissionError(AuthorizationFilterContext context)
        {
            context.HttpContext.Response.StatusCode = 403;
            context.Result = new ObjectResult(new BaseBizResult{ Success = false, Message = _localizationMgr.GetString(EnterpriseConsts.LocalizationSourceName, "PermissionDenied") });
            return;
        }
    }
}
